package com.ai.service.made.impl;

import com.ai.common.CommonResponse;
import com.ai.common.constant.HttpConstant;
import com.ai.common.constant.enumP.AlgorithmStateEnums;
import com.ai.common.constant.enumP.AvailableEnums;
import com.ai.entity.alarm.SwitchAlgorithmParam;
import com.ai.entity.function.FunctionPO;
import com.ai.entity.made.AlgorithmServerRelation;
import com.ai.entity.server.ServerPO;
import com.ai.mapper.made.AlgorithmServerRelationMapper;
import com.ai.model.param.DeployAlgorithmParam;
import com.ai.service.made.FunctionService;
import com.ai.service.made.IAlgorithmServerRelationService;
import com.ai.service.made.ServerService;
import com.ai.util.HttpRequestUtil;
import com.ai.util.SecurityUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jiaok
 * @since 2024-09-09
 */
@Service
@Slf4j
public class AlgorithmServerRelationServiceImpl extends ServiceImpl<AlgorithmServerRelationMapper, AlgorithmServerRelation> implements IAlgorithmServerRelationService {


    @Value("${api.switchAlgorithm.statusPath}")
    private String switchAlgorithmStatusPath;

    @Value("${api.switchAlgorithm.port}")
    private String switchAlgorithmPort;

    @Resource
    private ServerService serverService;


    @Resource
    private FunctionService functionService;

    @Override
    public void saveRelation(DeployAlgorithmParam deployAlgorithmParam, String algorithmFilePath) {

        /**
         * 先查看当前版本算法是否已经在目标服务器上部署过
         */
        QueryWrapper<AlgorithmServerRelation> queryWrapper = new QueryWrapper<AlgorithmServerRelation>().eq("function_id", deployAlgorithmParam.getFunctionId())
                .eq("server_id", deployAlgorithmParam.getServerId());
        List<AlgorithmServerRelation> algorithmServerRelationList = list(queryWrapper);
        if (!CollectionUtils.isEmpty(algorithmServerRelationList)){
            boolean b = algorithmServerRelationList.removeAll(algorithmServerRelationList);
        }

        /**
         * 添加新的关系
         */
        AlgorithmServerRelation algorithmServerRelation = new AlgorithmServerRelation();
        algorithmServerRelation.setAlgorithmId(Integer.valueOf(deployAlgorithmParam.getAlgorithmId()));
        algorithmServerRelation.setServerId(Integer.valueOf(deployAlgorithmParam.getServerId()));
        algorithmServerRelation.setFunctionId(Integer.valueOf(deployAlgorithmParam.getFunctionId()));
        algorithmServerRelation.setAlgorithmFilePath(algorithmFilePath);
        algorithmServerRelation.setAlgorithmState(AlgorithmStateEnums.NOT_START.getType());
        algorithmServerRelation.setIsAvailable(AvailableEnums.NOT_ENABLE.getType());
        algorithmServerRelation.setCreateUser(SecurityUtils.getLoginUserName());
        algorithmServerRelation.setCreateTime(LocalDateTime.now());
        algorithmServerRelation.setUpdateUser(SecurityUtils.getLoginUserName());
        algorithmServerRelation.setUpdateTime(LocalDateTime.now());
        //保存部署关系
        saveOrUpdate(algorithmServerRelation);
    }

    @Override
    public List<AlgorithmServerRelation> getDeployRelationList(String functionId) {

        FunctionPO functionPO = functionService.getById(functionId);

        QueryWrapper<AlgorithmServerRelation> relationQueryWrapper = new QueryWrapper<AlgorithmServerRelation>()
                .eq("function_id", functionId).orderByDesc("create_time");
        List<AlgorithmServerRelation> algorithmServerRelationList = list(relationQueryWrapper);

        //先判断该功能在哪台服务器上运行
        List<Integer> serverIdList = algorithmServerRelationList.stream().map(AlgorithmServerRelation::getServerId).distinct().collect(Collectors.toList());

        HashMap<Integer, String> statusMap = new HashMap<>(16);

        for (Integer serverId : serverIdList) {
            ServerPO serverPO = serverService.getById(serverId);
            try {
             //查询状态，无需修改运行状态
             String switchUrl = HttpConstant.HTTP_REQUEST_PREFIX + serverPO.getIp() +":"+ switchAlgorithmPort +  switchAlgorithmStatusPath;
             SwitchAlgorithmParam switchAlgorithmParam = new SwitchAlgorithmParam();
             switchAlgorithmParam.setAlgorithmType(String.valueOf(functionPO.getType()));
             String param = JSONObject.toJSONString(switchAlgorithmParam);
             log.info("===========================  请求算法路径：{}  ===========================",switchUrl);
             log.info("===========================  请求入参：{} ===========================",param);
             String res = HttpRequestUtil.sendPost(switchUrl, param);
             if (StringUtils.isBlank(res)){
                 log.error("=========================== {}  网络请求失败  ===========================",serverPO.getIp());
             }
             JSONObject jsonObject = JSONObject.parseObject(res);
             String code = jsonObject.getString("code");

             if (HttpConstant.SUCCESS_RES_CODE.equals(code)){
                 //获取运行状态
                 String status = jsonObject.getString("status");
                 statusMap.put(serverId,status);
             }else {
                 statusMap.put(serverId,AlgorithmStateEnums.ISException.getType());
                 log.error("=========================== {}  网络请求失败  ===========================",serverPO.getIp());
             }
         }catch (Exception e){
             log.error("===========================  网络连接失败：{}  ===========================",serverPO.getIp());
             statusMap.put(serverId,AlgorithmStateEnums.ISException.getType());
         }
        }

        for (AlgorithmServerRelation algorithmServerRelation : algorithmServerRelationList) {
            if (algorithmServerRelation.getIsAvailable().equals(AvailableEnums.ENABLE.getType())){
                //更新正在使用的算法状态
                algorithmServerRelation.setAlgorithmState(statusMap.get(algorithmServerRelation.getServerId()));
            }
        }

        return algorithmServerRelationList;
    }

    @Override
    public void isDeployedAndRunning(DeployAlgorithmParam deployAlgorithmParam) {

        QueryWrapper<AlgorithmServerRelation> queryWrapper = new QueryWrapper<AlgorithmServerRelation>().eq("function_id", deployAlgorithmParam.getFunctionId())
                .eq("server_id", deployAlgorithmParam.getServerId()).eq("algorithm_state",AlgorithmStateEnums.START.getType());
        AlgorithmServerRelation serverRelation = getOne(queryWrapper);
        if (null != serverRelation){
            throw new RuntimeException("当前算法正在目标服务运行，请停止后重新部署");
        }

    }

    @Override
    public boolean existAlgorithmRunning(String functionId) {

        QueryWrapper<AlgorithmServerRelation> relationQueryWrapper = new QueryWrapper<AlgorithmServerRelation>().eq("function_id", functionId).eq("algorithm_state", AlgorithmStateEnums.START.getType());
        List<AlgorithmServerRelation> serverRelationList = this.list(relationQueryWrapper);

        return CollectionUtils.isEmpty(serverRelationList);

    }

    @Override
    public void setAlgorithmStopStatus(String type, Integer serverId, Integer functionId, Integer algorithmId) {

        UpdateWrapper<AlgorithmServerRelation> updateWrapper = new UpdateWrapper<AlgorithmServerRelation>()
                .eq("server_id", serverId)
                .eq("function_id", functionId)
                .ne(null!=algorithmId,"algorithm_id", algorithmId)
                .set("algorithm_state", type)
                .set("is_available", AvailableEnums.NOT_ENABLE.getType());
        this.update(updateWrapper);
    }
}
